#ifndef __HTTP_INCLUDED__
#define __HTTP_INCLUDED__

#include <list>
#include <iostream>
#include <fstream>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>

class http_sanitize
{
public:
	typedef std::list<std::string> StringList;

	struct Request
	{
		std::string url;
		StringList http_header_row;

	};
	std::string getAttr2(std::string const& payload, std::string const& from, std::string const& to)
	{
		size_t start = payload.find(from);
		if(start == std::string::npos)
			return std::string();

		//start += from.size();

		size_t end = payload.find(to, start);
		if(end == std::string::npos)
			return std::string();

		return payload.substr(start, end - start);
	}

	std::string ReplaceAttr2(std::string subject, const std::string& search,
	                         const std::string& replace)
	{
		size_t pos = 0;
		while ((pos = subject.find(search, pos)) != std::string::npos)
		{
			subject.replace(pos, search.length(), replace);
			pos += replace.length();
		}
		return subject;
	}

	std::string Replace4(std::string subject, const std::string& search,
	                     const std::string& replace)
	{
		size_t pos = 0;
		while ((pos = subject.find(search, pos)) != std::string::npos)
		{
			subject.replace(pos, search.length(), replace);
			pos += replace.length();
		}
		return subject;
	}


	std::string extract4(std::string const& payload, std::string const& from, std::string const& to)
	{
		size_t start = payload.find(from);
		if(start == std::string::npos)
			return std::string();

		start += from.size();

		size_t end = payload.find(to, start);
		if(end == std::string::npos)
			return std::string();

		return payload.substr(start, end - start);
	}

	void RemoveHeaderAtt(std::string& payload, std::string const& att)
	{
		size_t start = payload.find(att);
		if(start == std::string::npos)
			return;


		size_t end = payload.find("\r\n", start);
		if(end == std::string::npos)
			return;

		end += 2; // We need \r\n

		payload.erase(start, end - start);
	}
	bool RemoveCookieAttr(std::string& payload, std::string const& att)
	{
		size_t start = payload.find(att);
		if(start == std::string::npos)
			return false;

		size_t lineEnd = payload.find("\r\n", start);
		size_t end = payload.find(";", start + 1);
///		if(end == std::string::npos)
//		{
//			end = payload.find("\r", start);
//		}
//		if(end == std::string::npos)
//			return false;
//		if(end > lineEnd)
//			return false;

		if(lineEnd < end || end == std::string::npos)
			end = lineEnd;

//		end += 1; // We need \r\n
//		std::cout << "len=" << end - start <<  " payload1=" << payload << std::endl;
		payload.erase(start, end - start);
//		std::cout << "payload2=" << payload << std::endl;
		return true;
	}


	void addHeaderRow(std::string const & row)
	{
		if( ! row.empty())
			m_toServer.http_header_row.push_back(row);
	}




	void requestHeaderFromClient(std::string const& requestHeader)
	{
//              fromClient = Replace(fromClient, "http://11","https://");
//              fromClient = Replace(fromClient, "http://1","https://");

		std::string host = getAttr2(requestHeader, "Host: ", "\r\n");
		host = ReplaceAttr2(host, "Host: 1","Host: ");
		addHeaderRow(host);


		std::string newCookie = getAttr2(requestHeader, "Cookie: ", "\r\n");
		newCookie = Replace4(newCookie, "http%3A%2F%2F1", "https%3A%2F%2F");
		addHeaderRow(newCookie);

		addHeaderRow(getAttr2(requestHeader, "Accept: ", "\r\n"));
		addHeaderRow(getAttr2(requestHeader, "User-Agent: ", "\r\n"));
		addHeaderRow(getAttr2(requestHeader, "Accept-Language: ", "\r\n"));

		// The rest is might exist
		addHeaderRow(getAttr2(requestHeader, "Content-Length: ", "\r\n"));

		std::string origin = getAttr2(requestHeader, "Origin: ", "\r\n");
		origin = ReplaceAttr2(origin, "http://1","https://");
		addHeaderRow(origin);

		std::string referer = getAttr2(requestHeader, "Referer: ", "\r\n");
		referer = ReplaceAttr2(referer, "http://1","https://");
		addHeaderRow(referer);



		//#####################################################
		std::string page = extract4(requestHeader, " ", " HTTP");
		std::string newUrl;
		std::string host2 = extract4(requestHeader, "Host: ", "\r\n");
		host2 = Replace4(host2, "11", "1");
		if(boost::starts_with(host2, "1"))
		{
			newUrl = "https://" + host2.substr(1) + page;
			newUrl = ReplaceAttr2(newUrl, "http://1","https://");
		}
		else
			newUrl = "http://" + host2 + page;
		//#####################################################

		newUrl = Replace4(newUrl, "http://www.1", "https://");
		newUrl = Replace4(newUrl, "http%3A%2F%2F1", "https%3A%2F%2F");
		m_toServer.url = newUrl;

		// DEBUG #####################################################
		static int id=0;
		++id;
		std::string idSt = boost::lexical_cast<std::string>(id);

		m_debug.open(std::string("processed/" + idSt + ".out").c_str());

		m_debug << "REQUEST HEADER FROM CLIENT ###################################\r\n";
		m_debug << requestHeader << "\r\n";
		m_debug << "REQUEST HEADER TO SERVER ####################################\r\n";
		m_debug << newUrl << "\r\n";

		for(http_sanitize::StringList::const_iterator row = m_toServer.http_header_row.begin() ; row != m_toServer.http_header_row.end(); ++row)
			m_debug << "Row=" << (*row) << "\r\n";

	}
	Request getRequestHeaderFromClient()
	{
		return m_toServer;
	}
	void requestBodyFromClient(std::string const& requestHeader)
	{
		m_request_body = Replace4(requestHeader, "http%3A%2F%2F1", "https%3A%2F%2F");

		m_debug << "REQUEST BODY FROM CLIENT ####################################\r\n";
		m_debug << "\r\n" << requestHeader << "\r\n";
		m_debug << "REQUEST BODY TO SERVER ####################################\r\n";
		m_debug << "\r\n" << m_request_body << "\r\n";
	}
	std::string getRequestBodyFromClient()
	{
		return m_request_body;
	}
	void responseHeaderFromServer(std::string const& responseHeader)
	{
		m_responseHeader = responseHeader;

		m_contentType = extract4(m_responseHeader,"Content-Type: ", "\r\n");

//		std::cout  << "RESPONSE HEADER FROM SERVER ####################################" << std::endl;
//		std::cout << "payload1=" << m_responseHeader << std::endl;

		m_responseHeader = Replace4(m_responseHeader, "https%3A%2F%2F", "http%3A%2F%2F1");
		m_responseHeader = Replace4(m_responseHeader, ":443", ":80");
		m_responseHeader = Replace4(m_responseHeader, "https://", "http://1");
		/*
				m_responseHeader = Replace4(m_responseHeader, ";Secure;HttpOnly;Priority=HIGH", "");
				m_responseHeader = Replace4(m_responseHeader, ";HttpOnly;Priority=HIGH", "");
				m_responseHeader = Replace4(m_responseHeader, "GMT;Priority=HIGH", "");
				m_responseHeader = Replace4(m_responseHeader, ";Path=/;Secure", "");
				m_responseHeader = Replace4(m_responseHeader, "; domain=mail.google.com;", ";");
				m_responseHeader = Replace4(m_responseHeader, "; Path=/; Secure", "");
				m_responseHeader = Replace4(m_responseHeader, "; Path=/; Secure; HttpOnly", "");
				m_responseHeader = Replace4(m_responseHeader, "; path=/mail; secure; HttpOnly", "");
				m_responseHeader = Replace4(m_responseHeader, ";Secure;Priority=HIGH", "");
				m_responseHeader = Replace4(m_responseHeader, ":443", ":80");
				m_responseHeader = Replace4(m_responseHeader, "; Secure;", ";");
				m_responseHeader = Replace4(m_responseHeader, "; Secure", "");
				m_responseHeader = Replace4(m_responseHeader, "; HttpOnly", "");
				m_responseHeader = Replace4(m_responseHeader, ";Priority=HIGH", "");
				m_responseHeader = Replace4(m_responseHeader, "; Path=/", "");
		*/
//		std::string test = "; Path=/; Secure; HttpOnl; domain=mail.google.com;";
//		std::cout << "testOld=" << test << std::endl;
		while(RemoveCookieAttr(m_responseHeader,"; Domain="));
		while(RemoveCookieAttr(m_responseHeader,"; domain="));
		while(RemoveCookieAttr(m_responseHeader,"; Path="));
		while(RemoveCookieAttr(m_responseHeader,"; path="));
		while(RemoveCookieAttr(m_responseHeader,"; Secure"));
		while(RemoveCookieAttr(m_responseHeader,"; secure"));
		while(RemoveCookieAttr(m_responseHeader,"; HttpOnly"));
		while(RemoveCookieAttr(m_responseHeader,"; Priority="));
		while(RemoveCookieAttr(m_responseHeader,"; priority="));

		while(RemoveCookieAttr(m_responseHeader,";Domain="));
		while(RemoveCookieAttr(m_responseHeader,";domain="));
		while(RemoveCookieAttr(m_responseHeader,";Path="));
		while(RemoveCookieAttr(m_responseHeader,";path="));
		while(RemoveCookieAttr(m_responseHeader,";Secure"));
		while(RemoveCookieAttr(m_responseHeader,";secure"));
		while(RemoveCookieAttr(m_responseHeader,";HttpOnly"));
		while(RemoveCookieAttr(m_responseHeader,";Priority="));
		while(RemoveCookieAttr(m_responseHeader,";priority="));

		RemoveHeaderAtt(m_responseHeader, "Transfer-Encoding");
		RemoveHeaderAtt(m_responseHeader, "Content-Encoding:");
		RemoveHeaderAtt(m_responseHeader, "Content-Security-Policy");
		RemoveHeaderAtt(m_responseHeader, "Strict-Transport-Security");
		RemoveHeaderAtt(m_responseHeader, "X-Frame-Options");
		RemoveHeaderAtt(m_responseHeader, "Alternate-Protocol");
		RemoveHeaderAtt(m_responseHeader, "X-XSS-Protection");

		std::cout << "Content-Type=:" << extract4(m_responseHeader,"Content-Type:", "\r\n") << std::endl;

		m_debug << "RESPONSE HEADER FROM SERVER ####################################\r\n";
		m_debug << responseHeader << "\r\n";
		m_debug << "RESPONSE HEADER TO CLIENT ####################################\r\n";
		m_debug << m_responseHeader << "\r\n";
	}
	std::string getRequestHeader()
	{
		return m_responseHeader;
	}
	void responseBodyFromServer(std::string const& responseBody)
	{
		m_responseBody = responseBody;

		if(boost::contains(m_contentType, "image/"))
			return;

		m_responseBody = Replace4(m_responseBody, "title>EOM", "title>YES");
		m_responseBody = Replace4(m_responseBody, "https://", "http://1");
		m_responseBody = Replace4(m_responseBody, "https:\\/\\/", "http:\\/\\/1");
		m_responseBody = Replace4(m_responseBody, "https%3A%2F%2F", "http%3A%2F%2F1");

		m_debug << "RESPONSE BODY FROM SERVER####################################\r\n";
		m_debug << responseBody << "\r\n";
		m_debug << "RESPONSE BODY TO CLIENT####################################\r\n";
		m_debug << m_responseBody << "\r\n";
	}
	std::string getResponseBody()
	{
		return m_responseBody;
	}
private:
	Request m_toServer;
	std::string m_request_body;
	std::ofstream m_debug;
	std::string m_responseHeader;
	std::string m_responseBody;
	std::string m_contentType;
};

#endif
